﻿using System;
using System.Collections.Generic;
using System.Text;

using RaisingStudio.Data.Expressions;
using System.Collections;
using RaisingStudio.Common.Reflection;

namespace RaisingStudio.Data.Common.Builders.Expressions
{
    /// <summary>
    /// Condition Command builder.
    /// </summary>
    public class ConditionExpressionCommandBuilder : ExpresssionCommandBuilder
    {
        #region static member
        /// <summary>
        /// Format string of parameter name.
        /// </summary>
        public const string PARAMETERNAMEFORMAT = "@pd{0}";


        public static string[] GetTableNamesFromTableExpressions(RaisingStudio.Data.Expressions.TableExpression[] tableExpressions)
        {
            string[] tableNames = new string[tableExpressions.Length];
            for (int i = 0; i < tableExpressions.Length; i++)
            {
                tableNames[i] = (string)tableExpressions[i];
            }
            return tableNames;
        }

        public static string[] GetColumnNamesFromColumnExpressions(RaisingStudio.Data.Expressions.ColumnExpression[] columnExpressions)
        {
            string[] columnNames = new string[columnExpressions.Length];
            for (int i = 0; i < columnExpressions.Length; i++)
            {
                columnNames[i] = (string)columnExpressions[i];
            }
            return columnNames;
        }

        public static Dictionary<string, string[]> GetColumnNamesFromColumnExpressions(Dictionary<RaisingStudio.Data.Expressions.TableExpression, RaisingStudio.Data.Expressions.ColumnExpression[]> columnExpressionsDictionary)
        {
            Dictionary<string, string[]> columnNamesDictionary = new Dictionary<string, string[]>();
            foreach (RaisingStudio.Data.Expressions.TableExpression tableExpression in columnExpressionsDictionary.Keys)
            {
                string tableName = (string)tableExpression;
                RaisingStudio.Data.Expressions.ColumnExpression[] columnExpressions = columnExpressionsDictionary[tableExpression];
                string[] columnNames = ConditionExpressionCommandBuilder.GetColumnNamesFromColumnExpressions(columnExpressions);

                columnNamesDictionary.Add(tableName, columnNames);
            }
            return columnNamesDictionary;
        }
        #endregion

        #region Common property 
        private bool useColumnsForParameterNames = false;
        /// <summary>
        /// If the value is true, it will generate the parameter name as column name (if possible), if it's false, it will generate @p1, @p2 like that.
        /// </summary>
        public bool UseColumnsForParameterNames
        {
            get
            {
                return this.useColumnsForParameterNames;
            }
            set
            {
                this.useColumnsForParameterNames = value;
            }
        }

        private RaisingStudio.Data.Expressions.ConditionExpression conditionExpression;
        public RaisingStudio.Data.Expressions.ConditionExpression ConditionExpression
        {
            get
            {
                return this.conditionExpression;
            }
            set
            {
                this.conditionExpression = value;
            }
        }

        private Dictionary<string, System.Data.DbType> dbTypes;

        public Dictionary<string, System.Data.DbType> DbTypes
        {
            get { return dbTypes; }
            set { dbTypes = value; }
        }

        private RaisingStudio.Data.Expressions.TableExpression tableExpression;

        public RaisingStudio.Data.Expressions.TableExpression TableExpression
        {
            get { return tableExpression; }
            set { tableExpression = value; }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// Constructor
        /// </summary>
        public ConditionExpressionCommandBuilder()
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="conditionExpression">condition expression.</param>
        public ConditionExpressionCommandBuilder(RaisingStudio.Data.Expressions.ConditionExpression conditionExpression, Dictionary<string, System.Data.DbType> dbTypes, RaisingStudio.Data.Expressions.TableExpression tableExpression)
        {
            this.conditionExpression = conditionExpression;
            this.dbTypes = dbTypes;
            this.tableExpression = tableExpression;
        }
        #endregion

        public static string GetSortingExpressionString(SortingExpression sortingExpression)
        {
            // 排序expression
            switch(sortingExpression.SortingDirection)
            {
                case SortingDirection.Ascending:
                    {
                        return string.Format("[{0}] ASC", sortingExpression.ColumnName);
                    }
                case SortingDirection.Descending:
                    {
                        return string.Format("[{0}] DESC", sortingExpression.ColumnName);
                    }
                default:
                    {
                        throw new NotSupportedException("Unknown sorting direction.");
                    }
            }
        }

        public static string GetColumnExpressionString(ColumnExpression columnExpression)
        {
            // Column expression.
            if (columnExpression is TableColumnExpression)
            {
                TableColumnExpression tableColumnExpression = columnExpression as TableColumnExpression;
                return string.Format(".[{0}].[{1}]", (string)tableColumnExpression.TableEpression, (string)tableColumnExpression);
            }
            else
            {
                return string.Format("[{0}]", (string)columnExpression);
            }
        }

        private static string GetTableExpressionString(TableExpression tableExpression)
        {
            return string.Format(".[{0}]", (string)tableExpression);
        }

        public static string GetFunctionExpressionString(FunctionExpression functionExpression, RaisingStudio.Data.Expressions.TableExpression tableExpression)
        {
            string tableExpressionString = GetTableExpressionString(tableExpression);
            ColumnExpression columnExpression = functionExpression.ColumnExpression;
            string columnExpressionString = GetColumnExpressionString(columnExpression);
            // Function expression
            switch (functionExpression.FunctionOperator)
            {
                case FunctionOperator.Avg:
                    {
                        return string.Format("(SELECT AVG({0}) FROM {1})", columnExpressionString, tableExpressionString);
                    }
                case FunctionOperator.Count:
                    {
                        return string.Format("(SELECT COUNT({0}) FROM {1})", columnExpressionString, tableExpressionString);
                    }
                case FunctionOperator.Max:
                    {
                        return string.Format("(SELECT MAX({0}) FROM {1})", columnExpressionString, tableExpressionString);
                    }
                case FunctionOperator.Min:
                    {
                        return string.Format("(SELECT MIN({0}) FROM {1})", columnExpressionString, tableExpressionString);
                    }
                case FunctionOperator.Sum:
                    {
                        return string.Format("(SELECT SUM({0}) FROM {1})", columnExpressionString, tableExpressionString);
                    }
                default:
                    {
                        throw new NotSupportedException("Unknown Function Operation 。");
                    }
            }
        }

        public static RaisingStudio.Data.CommonCommand GetBinaryExpressionCommand(BinaryExpression binaryExpression, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            RaisingStudio.Data.CommonCommand commonCommand = new CommonCommand();
            System.Text.StringBuilder commandTextStringBuilder = new StringBuilder();

            OperationElement operationElement = binaryExpression.OperationElement;
            if (binaryExpression.HasChildren)
            {
                if (!object.Equals(operationElement, null))
                {
                    commandTextStringBuilder.Append("(");
                    AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, operationElement, ref parameterNo, dbTypes, tableExpression);
                    switch (binaryExpression.BinaryOperator)
                    {
                        case BinaryOperator.Plus:
                            {
                                commandTextStringBuilder.Append(") + (");
                                break;
                            }
                        case BinaryOperator.Minus:
                            {
                                commandTextStringBuilder.Append(") - (");
                                break;
                            }
                        case BinaryOperator.Multiply:
                            {
                                commandTextStringBuilder.Append(") * (");
                                break;
                            }
                        case BinaryOperator.Divide:
                            {
                                commandTextStringBuilder.Append(") / (");
                                break;
                            }
                        case BinaryOperator.Modulo:
                            {
                                commandTextStringBuilder.Append(") % (");
                                break;
                            }
                        default:
                            {
                                // TODO: Unknown Operation 。
                                break;
                            }
                    }
                    AppendChildExpressionCommand(ref commandTextStringBuilder, ref commonCommand, binaryExpression, ref parameterNo, dbTypes, tableExpression);
                    commandTextStringBuilder.Append(")");
                }
                else
                {
                    commandTextStringBuilder.Append("(");
                    AppendChildExpressionCommand(ref commandTextStringBuilder, ref commonCommand, binaryExpression, ref parameterNo, dbTypes, tableExpression);
                    commandTextStringBuilder.Append(")");
                }
            }
            else
            {
                if (!object.Equals(operationElement, null))
                {
                    AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, operationElement, ref parameterNo, dbTypes, tableExpression);
                }
                else
                {
                    // TODO: Epxression is null.
                }
            }

            string commandText = commandTextStringBuilder.ToString();
            commonCommand.CommandText = commandText;
            return commonCommand;
        }

        public static RaisingStudio.Data.CommonCommand GetOperationExpressionCommand(OperationExpression operationExpression, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            RaisingStudio.Data.CommonCommand commonCommand = new CommonCommand();
            System.Text.StringBuilder commandTextStringBuilder = new StringBuilder();

            #region 元素
            if (operationExpression.Element is ColumnExpression)
            {
                // Column expression.
                ColumnExpression columnExpression = operationExpression.Element as ColumnExpression;
                string columnExpressionString = GetColumnExpressionString(columnExpression);
                commandTextStringBuilder.Append(columnExpressionString);
            }
            else if (operationExpression.Element is FunctionExpression)
            {
                // Function expression
                FunctionExpression functionExpression = operationExpression.Element as FunctionExpression;
                string functionExpressionString = GetFunctionExpressionString(functionExpression, tableExpression);
                commandTextStringBuilder.Append(functionExpressionString);
            }
            else if (operationExpression.Element is BinaryExpression)
            {
                // expression
                BinaryExpression binaryExpression = operationExpression.Element as BinaryExpression;
                RaisingStudio.Data.CommonCommand binaryExpressionCommand = GetBinaryExpressionCommand(binaryExpression, ref parameterNo, dbTypes, tableExpression);

                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, binaryExpressionCommand);
            }
            else if (operationExpression.Element is ValueExpression)
            {
                object value = (operationExpression.Element as ValueExpression).Value;
                // value.
                RaisingStudio.Data.CommonParameter commonParameter = new CommonParameter();
                string parameterName = string.Format(PARAMETERNAMEFORMAT, parameterNo);
                parameterNo++;
                commonParameter.ParameterName = parameterName;
                commonParameter.DbType = GetCommonParameterDbType(dbTypes, operationExpression);
                commonParameter.Value = value;

                commandTextStringBuilder.Append(parameterName);
                commonCommand.Parameters.Add(commonParameter);
            }
            else
            {
                // TODO: Unknown expression
            }
            #endregion
            #region Operation 符
            switch (operationExpression.Operator)
            {
                case ElementOperator.Equal:
                    {
                        commandTextStringBuilder.Append(" = ");
                        break;
                    }
                case ElementOperator.NotEqual:
                    {
                        commandTextStringBuilder.Append(" <> ");
                        break;
                    }
                case ElementOperator.Greater:
                    {
                        commandTextStringBuilder.Append(" > ");
                        break;
                    }
                case ElementOperator.GreaterOrEqual:
                    {
                        commandTextStringBuilder.Append(" >= ");
                        break;
                    }
                case ElementOperator.Less:
                    {
                        commandTextStringBuilder.Append(" < ");
                        break;
                    }
                case ElementOperator.LessOrEqual:
                    {
                        commandTextStringBuilder.Append(" <= ");
                        break;
                    }
                case ElementOperator.IsNull:
                    {
                        commandTextStringBuilder.Append(" IS NULL");
                        break;
                    }
                case ElementOperator.IsNotNull:
                    {
                        commandTextStringBuilder.Append(" IS NOT NULL");
                        break;
                    }
                case ElementOperator.Like:
                    {
                        commandTextStringBuilder.Append(" LIKE ");
                        break;
                    }
                case ElementOperator.NotLike:
                    {
                        commandTextStringBuilder.Append(" NOT LIKE ");
                        break;
                    }
                case ElementOperator.Between:
                    {
                        commandTextStringBuilder.Append(" BETWEEN ");
                        break;
                    }
                case ElementOperator.NotBetween:
                    {
                        commandTextStringBuilder.Append(" NOT BETWEEN ");
                        break;
                    }
                case ElementOperator.In:
                    {
                        commandTextStringBuilder.Append(" IN ");
                        break;
                    }
                case ElementOperator.NotIn:
                    {
                        commandTextStringBuilder.Append(" NOT IN ");
                        break;
                    }
            }
            #endregion
            #region 值
            if ((operationExpression.Operator != ElementOperator.IsNull) && (operationExpression.Operator != ElementOperator.IsNotNull))
            {
                if ((operationExpression.Operator == ElementOperator.Between) || (operationExpression.Operator == ElementOperator.NotBetween))
                {
                    if (operationExpression.Value is ICollection)
                    {
                        ICollection collection = operationExpression.Value as ICollection;
                        RaisingStudio.Data.CommonParameter minValueParameter = null;
                        string minValueParameterName = null;
                        RaisingStudio.Data.CommonParameter maxValueParameter = null;
                        string maxValueParameterName = null;
                        int i = 0;
                        foreach (object value in collection)
                        {
                            if (i == 0)
                            {
                                object minValue = value;
                                minValueParameter = new CommonParameter();
                                minValueParameterName = string.Format(PARAMETERNAMEFORMAT, parameterNo);
                                parameterNo++;
                                minValueParameter.ParameterName = minValueParameterName;
                                minValueParameter.Value = minValue;
                            }
                            else if (i == 1)
                            {
                                object maxValue = value;
                                maxValueParameter = new CommonParameter();
                                maxValueParameterName = string.Format(PARAMETERNAMEFORMAT, parameterNo);
                                parameterNo++;
                                maxValueParameter.ParameterName = maxValueParameterName;
                                maxValueParameter.Value = maxValue;
                            }
                            else
                            {
                                break;
                            }
                            i++;
                        }
                        if (minValueParameter != null && maxValueParameter != null)
                        {
#if (PocketPC || Smartphone || WindowsCE)
                            commandTextStringBuilder.Append(string.Format("{0} AND {1}", minValueParameterName, maxValueParameterName));
#else
                            commandTextStringBuilder.AppendFormat("{0} AND {1}", minValueParameterName, maxValueParameterName);
#endif
                            commonCommand.Parameters.Add(minValueParameter);
                            commonCommand.Parameters.Add(maxValueParameter);
                        }
                        else
                        {
                            throw new ArgumentException("进行 Between 或 NotBetween 时，data 值数组元素个数Not 能小于2。");
                        }
                    }
                    else
                    {
                        throw new ArgumentException("data 值type Not 正确，应该为数组Type.");
                    }
                }
                else if ((operationExpression.Operator == ElementOperator.In) || (operationExpression.Operator == ElementOperator.NotIn))
                {
                    if (operationExpression.Value is ICollection)
                    {
                        commandTextStringBuilder.Append("(");
                        ICollection collection = operationExpression.Value as ICollection;
                        int i = 0;
                        foreach(object value in collection)
                        {
                            RaisingStudio.Data.CommonParameter commonParameter = new CommonParameter();
                            string parameterName = string.Format(PARAMETERNAMEFORMAT, parameterNo);
                            parameterNo++;
                            commonParameter.ParameterName = parameterName;
                            //commonParameter.DbType = GetCommonParameterDbType(dbTypes, operationExpression);
                            commonParameter.Value = value;

                            if (i > 0)
                            {
                                commandTextStringBuilder.Append(", ");
                            }
                            
                            commandTextStringBuilder.Append(parameterName);
                            commonCommand.Parameters.Add(commonParameter);
                            i++;
                        }
                        commandTextStringBuilder.Append(")");
                    }
                    else
                    {
                        throw new ArgumentException("data 值type Not 正确，应该为数组Type.");
                    }
                }
                else
                {
                    #region 元素
                    if (operationExpression.Value is ColumnExpression)
                    {
                        // Column expression.
                        ColumnExpression columnExpression = operationExpression.Value as ColumnExpression;
                        string columnExpressionString = GetColumnExpressionString(columnExpression);
                        commandTextStringBuilder.Append(columnExpressionString);
                    }
                    else if (operationExpression.Value is FunctionExpression)
                    {
                        // Function expression
                        FunctionExpression functionExpression = operationExpression.Value as FunctionExpression;
                        string functionExpressionString = GetFunctionExpressionString(functionExpression, tableExpression);
                        commandTextStringBuilder.Append(functionExpressionString);
                    }
                    else if (operationExpression.Value is BinaryExpression)
                    {
                        // expression
                        BinaryExpression binaryExpression = operationExpression.Value as BinaryExpression;
                        RaisingStudio.Data.CommonCommand binaryExpressionCommand = GetBinaryExpressionCommand(binaryExpression, ref parameterNo, dbTypes, tableExpression);

                        AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, binaryExpressionCommand);
                    }
                    #endregion
                    else
                    {
                        object value = operationExpression.Value;
                        // values.
                        RaisingStudio.Data.CommonParameter commonParameter = new CommonParameter();
                        string parameterName = string.Format(PARAMETERNAMEFORMAT, parameterNo);
                        parameterNo++;
                        commonParameter.ParameterName = parameterName;
                        commonParameter.DbType = GetCommonParameterDbType(dbTypes, operationExpression);
                        commonParameter.Value = value;

                        commandTextStringBuilder.Append(parameterName);
                        commonCommand.Parameters.Add(commonParameter);
                    }
                }
            }
            #endregion

            string commandText = commandTextStringBuilder.ToString();
            commonCommand.CommandText = commandText;
            return commonCommand;
        }

        public static RaisingStudio.Data.CommonCommand GetRelationExpressionCommand(RelationExpression relationExpression, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            RaisingStudio.Data.CommonCommand commonCommand = new CommonCommand();
            System.Text.StringBuilder commandTextStringBuilder = new StringBuilder();

            ExpressionElement expressionElement = relationExpression.ExpressionElement;
            if (relationExpression.HasChildren)
            {
                if (expressionElement != null)
                {
                    switch (relationExpression.RelationOperator)
                    {
                        case RelationOperator.And:
                            {
                                commandTextStringBuilder.Append("(");
                                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, expressionElement, ref parameterNo, dbTypes, tableExpression);
                                commandTextStringBuilder.Append(") AND (");
                                AppendChildExpressionCommand(ref commandTextStringBuilder, ref commonCommand, relationExpression, ref parameterNo, dbTypes, tableExpression);
                                commandTextStringBuilder.Append(")");
                                break;
                            }
                        case RelationOperator.Or:
                            {
                                commandTextStringBuilder.Append("(");
                                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, expressionElement, ref parameterNo, dbTypes, tableExpression);
                                commandTextStringBuilder.Append(") OR (");
                                AppendChildExpressionCommand(ref commandTextStringBuilder, ref commonCommand, relationExpression, ref parameterNo, dbTypes, tableExpression);
                                commandTextStringBuilder.Append(")");
                                break;
                            }
                        default:
                            {
                                // TODO: Other Relation 。
                                break;
                            }
                    }
                }
                else
                {
                    commandTextStringBuilder.Append("(");
                    AppendChildExpressionCommand(ref commandTextStringBuilder, ref commonCommand, relationExpression, ref parameterNo, dbTypes, tableExpression);
                    commandTextStringBuilder.Append(")");
                }
            }
            else
            {
                if (expressionElement != null)
                {
                    if (relationExpression.RelationOperator == RelationOperator.Not)
                    {
                        commandTextStringBuilder.Append("( NOT (");
                        AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, expressionElement, ref parameterNo, dbTypes, tableExpression);
                        commandTextStringBuilder.Append("))");
                    }
                    else
                    {
                        AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, expressionElement, ref parameterNo, dbTypes, tableExpression);
                    }
                }
                else
                {
                    // TODO: Epxression 为Is null.
                }
            }

            string commandText = commandTextStringBuilder.ToString();
            commonCommand.CommandText = commandText;
            return commonCommand;
        }

        private static void AppendChildExpressionCommand(ref System.Text.StringBuilder commandTextStringBuilder, ref RaisingStudio.Data.CommonCommand commonCommand, RelationExpression relationExpression, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            bool relationExpressionSplitted = false;
            // Add child Relation 。
            foreach (RelationExpression childExpression in relationExpression.Children)
            {
                if (relationExpressionSplitted)
                {
                    #region Split Relation Epxression 
                    switch (childExpression.RelationOperator)
                    {
                        case RelationOperator.And:
                            {
                                commandTextStringBuilder.Append(") AND (");
                                break;
                            }
                        case RelationOperator.Or:
                            {
                                commandTextStringBuilder.Append(") OR (");
                                break;
                            }
                        default:
                            {
                                // TODO: Other Relation 。
                                break;
                            }
                    }
                    #endregion
                }
                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, childExpression, ref parameterNo, dbTypes, tableExpression);
                relationExpressionSplitted = true;
            }
        }

        private static void AppendExpressionCommand(ref System.Text.StringBuilder commandTextStringBuilder, ref RaisingStudio.Data.CommonCommand commonCommand, ExpressionElement expressionElement, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            if (expressionElement is OperationExpression)
            {
                // Operation expression
                OperationExpression operationExpression = expressionElement as OperationExpression;
                RaisingStudio.Data.CommonCommand operationExpressionCommand = GetOperationExpressionCommand(operationExpression, ref parameterNo, dbTypes, tableExpression);

                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, operationExpressionCommand);
            }
            else if (expressionElement is RelationExpression)
            {
                // Operation expression
                RelationExpression relationExpression = expressionElement as RelationExpression;
                RaisingStudio.Data.CommonCommand relationExpressionCommand = GetRelationExpressionCommand(relationExpression, ref parameterNo, dbTypes, tableExpression);

                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, relationExpressionCommand);
            }
            else
            {
                // TODO: Unknown expression
                throw new NotSupportedException("Unknown Epxression Type.");
            }
        }
        
        private static void AppendExpressionCommand(ref System.Text.StringBuilder commandTextStringBuilder, ref RaisingStudio.Data.CommonCommand commonCommand, RaisingStudio.Data.CommonCommand expressionCommand)
        {
            commandTextStringBuilder.Append(expressionCommand.CommandText);
            if (expressionCommand.HasParameters)
            {
                foreach (RaisingStudio.Data.CommonParameter parameter in expressionCommand.Parameters)
                {
                    commonCommand.Parameters.Add(parameter);
                }
            }
        }

        private static void AppendChildExpressionCommand(ref System.Text.StringBuilder commandTextStringBuilder, ref RaisingStudio.Data.CommonCommand commonCommand, BinaryExpression binaryExpression, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            bool binaryExpressionSplitted = false;
            // Add child Operation 。
            foreach (BinaryExpression childExpression in binaryExpression.Children)
            {
                if (binaryExpressionSplitted)
                {
                    #region Split Operation Epxression 
                    switch (childExpression.BinaryOperator)
                    {
                        case BinaryOperator.Plus:
                            {
                                commandTextStringBuilder.Append(" + ");
                                break;
                            }
                        case BinaryOperator.Minus:
                            {
                                commandTextStringBuilder.Append(" - ");
                                break;
                            }
                        case BinaryOperator.Multiply:
                            {
                                commandTextStringBuilder.Append(" * ");
                                break;
                            }
                        case BinaryOperator.Divide:
                            {
                                commandTextStringBuilder.Append(" / ");
                                break;
                            }
                        case BinaryOperator.Modulo:
                            {
                                commandTextStringBuilder.Append(" % ");
                                break;
                            }
                        default:
                            {
                                // TODO: Unknown Operation 。
                                break;
                            }
                    }
                    #endregion
                }
                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, childExpression, ref parameterNo, dbTypes, tableExpression);
                binaryExpressionSplitted = true;
            }
        }

        private static void AppendExpressionCommand(ref System.Text.StringBuilder commandTextStringBuilder, ref RaisingStudio.Data.CommonCommand commonCommand, OperationElement operationElement, ref int parameterNo, Dictionary<string, System.Data.DbType> dbTypes, TableExpression tableExpression)
        {
            #region 元素
            if (operationElement is ColumnExpression)
            {
                // Column expression.
                ColumnExpression columnExpression = operationElement as ColumnExpression;
                string columnExpressionString = GetColumnExpressionString(columnExpression);
                commandTextStringBuilder.Append(columnExpressionString);
            }
            else if (operationElement is FunctionExpression)
            {
                // Function expression
                FunctionExpression functionExpression = operationElement as FunctionExpression;
                string functionExpressionString = GetFunctionExpressionString(functionExpression, tableExpression);
                commandTextStringBuilder.Append(functionExpressionString);
            }
            else if (operationElement is BinaryExpression)
            {
                // expression
                BinaryExpression binaryExpression = operationElement as BinaryExpression;
                RaisingStudio.Data.CommonCommand binaryExpressionCommand = GetBinaryExpressionCommand(binaryExpression, ref parameterNo, dbTypes, tableExpression);

                AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, binaryExpressionCommand);
            }
            #endregion
            else if (operationElement is ValueExpression)
            {
                ValueExpression valueExpression = operationElement as ValueExpression;
                object value = valueExpression.Value;
                // values.
                RaisingStudio.Data.CommonParameter commonParameter = new CommonParameter();
                string parameterName = string.Format(PARAMETERNAMEFORMAT, parameterNo);
                parameterNo++;
                commonParameter.ParameterName = parameterName;
                commonParameter.DbType = GetCommonParameterDbType(dbTypes, operationElement);
                commonParameter.Value = value;

                commandTextStringBuilder.Append(parameterName);
                commonCommand.Parameters.Add(commonParameter);
            }
            else
            {
                // TODO: Unknown Type.
            }
        }

        public override RaisingStudio.Data.CommonCommand GetExpressionCommand()
        {
            if (this.conditionExpression != null)
            {
                RaisingStudio.Data.CommonCommand commonCommand = new CommonCommand();
                System.Text.StringBuilder commandTextStringBuilder = new StringBuilder();
                #region 筛选
                if (conditionExpression.ExpressionElement != null)
                {
                    commandTextStringBuilder.Append("WHERE ");
                    #region 解析Epxression 
                    int parameterNo = 1;
                    ExpressionElement expressionElement = conditionExpression.ExpressionElement;
                    AppendExpressionCommand(ref commandTextStringBuilder, ref commonCommand, expressionElement, ref parameterNo, dbTypes, tableExpression);
                    #endregion
                }
                #endregion
                #region 排序
                if (conditionExpression.HasSortingExpressions)
                {
                    if (commandTextStringBuilder.Length > 0)
                    {
                        commandTextStringBuilder.Append(" ");
                    }
                    commandTextStringBuilder.Append("ORDER BY ");
                    
                    bool sortingExpressionStringSplitted = false;
                    foreach (SortingExpression sortingExpression in conditionExpression.SortingExpressions)
                    {
                        string sortingExpressionString = GetSortingExpressionString(sortingExpression);
                        if (sortingExpressionStringSplitted)
                        {
                            commandTextStringBuilder.Append(", ");
                        }
                        commandTextStringBuilder.Append(sortingExpressionString);
                        sortingExpressionStringSplitted = true;
                    }
                }
                #endregion
                string commandText = commandTextStringBuilder.ToString();
                commonCommand.CommandText = commandText;
                return commonCommand;
            }
            else
            {
                return null;
            }
        }


        public static System.Data.DbType GetDbType(object value)
        {
            System.Data.DbType dbType = System.Data.DbType.String;
            if (value != null)
            {
                Type type = value.GetType();
                dbType = TypeManager.GetWellKnownDbType(TypeManager.GetWellKnownDataTypeName(type));
            }
            return dbType;
        }

        public static System.Data.DbType GetCommonParameterDbType(Dictionary<string, System.Data.DbType> dbTypes, OperationExpression operationExpression)
        {
            if (operationExpression.Element is TableColumnExpression)
            {
                TableColumnExpression tableColumnExpression = operationExpression.Element as TableColumnExpression;
                string columnName = string.Format("{0}.{1}", (string)tableColumnExpression.TableEpression, (string)tableColumnExpression);
                if (dbTypes.ContainsKey(columnName))
                {
                    return dbTypes[columnName];
                }
            }
            else if (operationExpression.Element is ColumnExpression)
            {
                ColumnExpression columnExpression = operationExpression.Element as ColumnExpression;
                string columnName = (string)columnExpression;
                if (dbTypes.ContainsKey(columnName))
                {
                    return dbTypes[columnName];
                }
            }
            else if (operationExpression.Element is ValueExpression)
            {
                // TODO: get dbType by value type.
                return GetDbType((operationExpression.Element as ValueExpression).Value);
            }
            return System.Data.DbType.String;
        }

        public static System.Data.DbType GetCommonParameterDbType(Dictionary<string, System.Data.DbType> dbTypes, OperationElement operationElement)
        {
            if (operationElement is TableColumnExpression)
            {
                TableColumnExpression tableColumnExpression = operationElement as TableColumnExpression;
                string columnName = string.Format("{0}.{1}", (string)tableColumnExpression.TableEpression, (string)tableColumnExpression);
                if (dbTypes.ContainsKey(columnName))
                {
                    return dbTypes[columnName];
                }
            }
            else if (operationElement is ColumnExpression)
            {
                ColumnExpression columnExpression = operationElement as ColumnExpression;
                string columnName = (string)columnExpression;
                if (dbTypes.ContainsKey(columnName))
                {
                    return dbTypes[columnName];
                }
            }
            else if (operationElement is ValueExpression)
            {
                // TODO: get dbType by value type.
                return GetDbType((operationElement as ValueExpression).Value);
            }
            return System.Data.DbType.String;
        }
    }
}
